package chain

import (
	"encoding/json"
	"fmt"
	"math/big"
	"strconv"
	"strings"
)

func (c *Client) BlockNumber() (uint64, error) {
	var n string
	err := c.rpcClient.Call(&n, "eth_blockNumber")
	if err != nil {
		return 0, err
	}
	afterN := strings.Split(n, "0x")
	blockNumber, err := strconv.ParseInt(afterN[1], 16, 64)
	if err != nil {
		return 0, err
	}
	return uint64(blockNumber), nil
}
func (c *Client) GetBlockByBlockNumOrHash(input string) (*Block, error) {
	var arg string
	var method string
	tmp := strings.Split(input, "0x")
	switch len(tmp) {
	case 1: // 是块高
		method = "eth_getBlockByNumber"
		hexString, err := ToHexString(input)
		if err != nil {
			return nil, err
		}
		arg = *hexString
	case 2: // 是hash
		method = "eth_getBlockByHash"
		arg = input
	default:
		return nil, fmt.Errorf("arg is invalid")
	}
	var res interface{}
	err := c.rpcClient.Call(&res, method, arg, true)
	if err != nil {
		return nil, err
	}
	if res == nil {
		return nil, fmt.Errorf("当前的提供的参数%v链上不存在对应的块", arg)
	}
	blockInfo, err := json.MarshalIndent(res, "", "	")
	if err != nil {
		return nil, err
	}
	var block Block
	err = json.Unmarshal(blockInfo, &block)
	if err != nil {
		return nil, err
	}
	err = ExchangeBlock(&block)
	if err != nil {
		return nil, err
	}
	return &block, nil
}
func ToHexString(q string) (*string, error) {
	v, success := big.NewInt(0).SetString(q, 0)
	if !success {
		return nil, fmt.Errorf("invalid input")
	}
	if v.Cmp(big.NewInt(0)) < 0 {
		return nil, fmt.Errorf("quantity must be larger than -1")
	}
	hexString := "0x" + v.Text(16)
	return &hexString, nil
}
func ExchangeBlock(inputBlock interface{}) error {
	switch inputBlock.(type) {
	case *Block:
		block := inputBlock.(*Block)
		err := ExchangeBlockHeader(block)
		if err != nil {
			return err
		}
		for i := range block.Uncles {
			err = ExchangeUncleHeader(&block.Uncles[i])
			if err != nil {
				return err
			}
		}
		for i := range block.Transactions {
			err = ExchangeBlockTransaction(&block.Transactions[i])
			if err != nil {
				return err
			}
		}
	case *MixedBlock:
		block := inputBlock.(*MixedBlock)
		err := ExchangeBlockHeader(block)
		if err != nil {
			return err
		}
		for i := range block.Uncles {
			err = ExchangeUncleHeader(&block.Uncles[i])
			if err != nil {
				return err
			}
		}
		for i := range block.Transactions {
			err = ExchangeBlockTransaction(&block.Transactions[i])
			if err != nil {
				return err
			}
		}
	}
	return nil
}

type MixedBlock struct {
	// Header       Header
	ParentHash      string           `json:"parentHash"`
	UncleHash       string           `json:"sha3Uncles"`
	Coinbase        string           `json:"miner"`
	Root            string           `json:"stateRoot"`
	TxHash          string           `json:"transactionsRoot"`
	ReceiptHash     string           `json:"receiptsRoot"`
	Bloom           string           `json:"logsBloom"`
	Difficulty      string           `json:"difficulty"`
	Number          string           `json:"number"`
	GasLimit        string           `json:"gasLimit"`
	GasUsed         string           `json:"gasUsed"`
	Time            string           `json:"timestamp"`
	Extra           string           `json:"extraData"`
	MixDigest       string           `json:"mixHash"`
	Nonce           string           `json:"nonce"`
	TotalDifficulty string           `json:"totalDifficulty"`
	Size            string           `json:"size"`
	Hash            string           `json:"hash"`
	Uncles          []Header         `json:"uncles"`
	Transactions    []MixTransaction `json:"transactions"`
}

type Block struct {
	// Header       Header
	ParentHash      string        `json:"parentHash"`
	UncleHash       string        `json:"sha3Uncles"`
	Coinbase        string        `json:"miner"`
	Root            string        `json:"stateRoot"`
	TxHash          string        `json:"transactionsRoot"`
	ReceiptHash     string        `json:"receiptsRoot"`
	Bloom           string        `json:"logsBloom"`
	Difficulty      string        `json:"difficulty"`
	Number          string        `json:"number"`
	GasLimit        string        `json:"gasLimit"`
	GasUsed         string        `json:"gasUsed"`
	Time            string        `json:"timestamp"`
	Extra           string        `json:"extraData"`
	MixDigest       string        `json:"mixHash"`
	Nonce           string        `json:"nonce"`
	TotalDifficulty string        `json:"totalDifficulty"`
	Size            string        `json:"size"`
	Hash            string        `json:"hash"`
	Uncles          []Header      `json:"uncles"`
	Transactions    []Transaction `json:"transactions"`
}
